package com.zijidelu.luframework.starter.translate;

import cn.hutool.core.util.ReflectUtil;
import com.zijidelu.luframework.utils.CastUtil;
import com.zijidelu.luframework.utils.lang.reflect.bean.XReflectUtil;
import com.zijidelu.luframework.base.dict.Dict;
import com.zijidelu.luframework.base.dict.DictField;
import com.zijidelu.luframework.base.dict.DictTranslatable;
import com.zijidelu.luframework.base.exception.sys.DictTranslationException;
import com.zijidelu.luframework.config.properties.LuFrameworkProperties;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 翻译工具类。
 *
 * @author ZIJIDELU
 * @datetime 2025/10/15 22:17
 */
@Slf4j
@Component
public class DictTranslateUtil {
    private static LuFrameworkProperties luFrameworkProperties;

    @Autowired
    public void setLuFrameworkProperties(LuFrameworkProperties luFrameworkProperties) {
        DictTranslateUtil.luFrameworkProperties = luFrameworkProperties;
    }

    /**
     * 检查是否为严格模式
     */
    public static boolean isStrictMode() {
        return luFrameworkProperties.getDict().isStrictMode();
    }

    /**
     * 翻译枚举值（强类型版本）。
     */
    public static <K, V, T extends Enum<T> & Dict<K, V>> V translate(Class<T> dictClass, K key) {
        T dict = Dict.getByKey(dictClass, key);
        if (dict == null) {
            throw DictTranslationException.keyNotFound(dictClass, key);
        }
        return dict.getValue();
    }

    /**
     * 反向翻译枚举值（强类型版本）。
     */
    public static <K, V, T extends Enum<T> & Dict<K, V>> K reverseTranslate(Class<T> dictClass, V value) {
        T dict = Dict.getByValue(dictClass, value);
        if (dict == null) {
            throw DictTranslationException.valueNotFound(dictClass, value);
        }
        return dict.getKey();
    }

    /**
     * 翻译对象中的枚举值。
     *
     * @param data 对象
     */
    public static <T> void translateObject(final T data) {
        if (Objects.isNull(data)) {
            log.warn("对象为空，无法翻译");
            return;
        }

        final Map<DictTranslatable, Map<Field, Object>> translatableObjects = collectTranslatableObjectsBfs(data);
        // 翻译所有 DictTranslatable 对象
        translatableObjects.forEach((translatable, fieldObjectMap) -> {
            if (translatable.dictStrategy() == DictTranslatable.DictTranslateStrategy.MAPPING) {
                translatable.processDictMapping(isStrictMode());
            } else if (translatable.dictStrategy() == DictTranslatable.DictTranslateStrategy.ANNOTATION) {
                annotationTranslateObject(translatable, fieldObjectMap);
            }
        });

    }

    /**
     * 使用广度优先搜索(BFS)收集对象图中所有实现了 DictTranslatable 接口的对象及其字段信息。
     *
     * @param root 根对象
     * @return 一个 Map，键是所有找到的 DictTranslatable 对象，值是该对象所有字段（Field）到其值（Object）的映射。
     */
    private static Map<DictTranslatable, Map<Field, Object>> collectTranslatableObjectsBfs(final Object root) {
        if (root == null) {
            return Collections.emptyMap();
        }

        // IdentityHashMap 是处理对象图遍历的最佳实践，用 == 比较对象实例
        final Map<Object, Boolean> visited = new IdentityHashMap<>();
        final Deque<Object> queue = new ArrayDeque<>();
        // 最终结果：每个 DictTranslatable 对象 -> 其字段名和值的映射
        final Map<DictTranslatable, Map<Field, Object>> result = new IdentityHashMap<>();

        // 从根对象开始 BFS 遍历
        processTranslatableElements(root, visited, queue);
        // 根对象存在不是DictTranslatable的情况，故需要分析其处理字段
        final Map<Field, Object> rootFieldObjectMap = populateFieldMap(root);
        rootFieldObjectMap.forEach((key, value) -> processTranslatableElements(value, visited, queue));
        if (root instanceof DictTranslatable translatable) {
            result.put(translatable, rootFieldObjectMap);
        }

        while (!queue.isEmpty()) {
            final Object currentObj = queue.poll();

            // 如果当前对象是 DictTranslatable，则收集其所有字段信息
            if (currentObj instanceof DictTranslatable translatable) {
                // 避免重复处理同一个对象（虽然 visited 队列层已经防重复，但这里更保险）
                if (!result.containsKey(translatable)) {
                    final Map<Field, Object> fieldObjectMap = populateFieldMap(translatable);
                    fieldObjectMap.forEach((key, value) -> processTranslatableElements(value, visited, queue));
                    result.put(translatable, fieldObjectMap);
                }
            }

        }

        return result;
    }

    /**
     * 将对象添加到队列中，前提是该对象未被访问过。
     *
     * @param obj     待添加的对象
     * @param visited 已访问对象的映射，用于防止重复处理
     * @param queue   待处理对象的队列，用于 BFS 遍历
     */
    private static void addQueue(final Object obj,
                                 final Map<Object, Boolean> visited,
                                 final Deque<Object> queue) {
        if (obj == null) {
            return;
        }

        if (!visited.containsKey(obj)) {
            if (obj instanceof DictTranslatable) {
                visited.put(obj, true);
                queue.add(obj);
            }
        }
    }

    /**
     * 处理集合类型对象，将其中的 DictTranslatable 元素添加到队列中。
     *
     * @param obj     待处理的对象，必须是集合类型（Collection 或 Map）
     * @param visited 已访问对象的映射，用于防止重复处理
     * @param queue   待处理对象的队列，用于 BFS 遍历
     */
    private static void processTranslatableElements(final Object obj,
                                                    final Map<Object, Boolean> visited,
                                                    final Deque<Object> queue
    ) {
        switch (obj) {
            // 处理 DictTranslatable 接口实现类
            case DictTranslatable ignored -> addQueue(obj, visited, queue);

            case Collection<?> collection -> {
                // 处理集合
                for (Object o : collection) {
                    addQueue(o, visited, queue);
                }
            }

            case Map<?, ?> map -> {
                // 处理映射
                for (Map.Entry<?, ?> entry : map.entrySet()) {
                    final Object value = entry.getValue();
                    final Object key = entry.getKey();
                    addQueue(value, visited, queue);
                    addQueue(key, visited, queue);
                }
            }

            case null, default -> {
            }

        }

    }

    /**
     * 填充一个对象的所有字段信息到 Map 中。
     *
     * @param obj 目标对象
     * @return Map<Field, Object>，包含对象的所有字段及其值,值可能为null
     */
    private static Map<Field, Object> populateFieldMap(final Object obj) {
        final Class<?> objClass = obj.getClass();
        final Map<Field, Object> fieldMap = new LinkedHashMap<>();
        // 获取所有字段(包含父类)
        final Field[] declaredFields = ReflectUtil.getFields(objClass);
        final XReflectUtil<?> fieldReflect = XReflectUtil.of(objClass);

        for (Field field : declaredFields) {
            final Object fieldValue = fieldReflect.getFieldValue(obj, field.getName());
            fieldMap.put(field, fieldValue);
        }

        return fieldMap;
    }

    /**
     * 处理注解翻译
     *
     * @param data           待翻译的对象
     * @param fieldObjectMap 字段值映射，键为字段，值为字段对应的值
     * @param <T>            对象类型
     */
    private static <T> void annotationTranslateObject(final T data,
                                                      final Map<Field, Object> fieldObjectMap) {
        final Class<T> dataClass = CastUtil.cast(data.getClass());
        final XReflectUtil<T> xReflectUtil = XReflectUtil.of(dataClass);
        final Set<String> declaredFieldNameSet = fieldObjectMap.keySet().stream().map(Field::getName).collect(Collectors.toSet());
        fieldObjectMap.forEach((field, value) -> {
            // 字段值为空，跳过
            if (value == null) {
                return;
            }

            final DictField translateField = field.getAnnotation(DictField.class);
            if (translateField == null) {
                return;
            }

            // 获取目标字段
            final String targetFieldName = translateField.targetFieldName();
            // 目标字段为空，跳过
            if (StringUtils.isBlank(targetFieldName)) {
                final String msg = String.format("目标字段 '%s' 为空，翻译失败 (注解: %s)", targetFieldName, DictField.class.getName());
                log.warn(msg);
                if (!isStrictMode()) {
                    // 非严格模式下，忽略翻译异常
                    return;
                } else {
                    throw new DictTranslationException(msg);
                }
            }
            // 目标字段不存在，跳过
            if (!declaredFieldNameSet.contains(targetFieldName)) {
                final String msg = String.format("目标字段 '%s' 在类型 %s 中不存在，翻译失败", targetFieldName, dataClass.getName());
                log.error(msg);
                if (!isStrictMode()) {
                    // 非严格模式下，忽略翻译异常
                    return;
                } else {
                    throw new DictTranslationException(msg);
                }
            }

            if (!isStrictMode()) {
                // 非严格模式下，忽略翻译异常
                try {
                    if (translateField.reverse()) {
                        xReflectUtil.setFieldValue(data, targetFieldName, reverseTranslate(CastUtil.cast(translateField.value()), value));
                    } else {
                        // 翻译字段值
                        xReflectUtil.setFieldValue(data, targetFieldName, translate(CastUtil.cast(translateField.value()), value));
                    }
                } catch (DictTranslationException ignored) {
                    // 非严格模式下，忽略翻译异常
                }
            } else {
                if (translateField.reverse()) {
                    xReflectUtil.setFieldValue(data, targetFieldName, reverseTranslate(CastUtil.cast(translateField.value()), value));
                } else {
                    // 翻译字段值
                    xReflectUtil.setFieldValue(data, targetFieldName, translate(CastUtil.cast(translateField.value()), value));
                }
            }

        });

    }

}
